package com.dtruth.dataflow.util;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.log4j.Logger;

/**
 * 
 * @author 岳海亮
 * @email yhl@feheadline.com
 * @date 2014年11月4日
 */
public class StringUtil {
	private static Logger logger = Logger.getLogger(StringUtil.class);

	/**
	 * 16进制转 10 进制
	 */
	public long xh2int(String hxString) {
		return Long.parseLong(hxString, 16);
	}

	/**
	 * 给定位数的16进制转数的最大值
	 * 
	 * @param hxStrLen
	 *            16进制数位数
	 */
	public double maxValueOfXHLenth(int hxStrLen) {
		return Math.pow(16, hxStrLen) - 1;
	}

	/**
	 * 判断字符串是否为空:true->为空串
	 * 
	 * @return null 或长度为0 返回true 否则返回false
	 */
	public static boolean isEmpty(String source) {
		return source == null || source.trim().isEmpty();
	}

	/**
	 * 判断字符串是否为正整数值 如果串为空则
	 */
	public static boolean isPositiveNumber(String numberStr) {
		return ("" + numberStr).matches("\\d{1,}");
	}

	/**
	 * 将字符串转为整数 如果串为空则
	 */
	public static int getIntValue(String numberStr) {
		return Integer.parseInt(numberStr);
	}

	/**
	 * 将字符串转为整数 如果串为空则
	 */
	public static float getFlaotValue(String falatStr) {
		return Float.parseFloat(falatStr);
	}

	/**
	 * 将字符串转为整数 如果串为空则
	 */
	public static long getLongValue(String longStr) {
		return Long.parseLong(longStr);
	}

	/**
	 * MD5 加密
	 */
	public static String getMd5(String src) {

		MessageDigest messageDigest = null;

		try {
			messageDigest = MessageDigest.getInstance("MD5");

			messageDigest.reset();

			messageDigest.update(src.getBytes("UTF-8"));
		} catch (UnsupportedEncodingException ex) {
			logger.warn(ex.getMessage());
		} catch (NoSuchAlgorithmException e) {
			logger.warn(e.getMessage());
		}

		byte[] byteArray = messageDigest.digest();

		StringBuffer md5StrBuff = new StringBuffer();

		for (int i = 0; i < byteArray.length; i++) {
			if (Integer.toHexString(0xFF & byteArray[i]).length() == 1)
				md5StrBuff.append("0").append(
						Integer.toHexString(0xFF & byteArray[i]));
			else
				md5StrBuff.append(Integer.toHexString(0xFF & byteArray[i]));
		}
		return md5StrBuff.toString();
	}

	/**
	 * 是否为数字（包含小数）
	 * 
	 * @param str
	 * @return
	 */
	public static boolean isNumeric(String str) {
		Pattern pattern = Pattern.compile("^[0-9]+\\.?[0-9]+$");
		return pattern.matcher(str).matches();
	}

	/**
	 * 判断字符串是否为英文字符串
	 * 
	 * @param str
	 * @return
	 */
	public static boolean isENString(String str) {
		Pattern pattern = Pattern.compile("[a-zA-Z]{1,}");
		Matcher matcher = pattern.matcher((CharSequence) str);
		return matcher.matches();
	}

	public static boolean containsCNStr(String input) {
		Pattern pattern = Pattern.compile("[\u4e00-\u9fa5]+");
		Matcher matcher = pattern.matcher((CharSequence) input);
		return matcher.find();
	}

	public static boolean isZero(String str) {
		Pattern pattern = Pattern.compile("^0+(\\.0+)?$");
		return pattern.matcher(str).matches();
	}

	/**
	 * 将字符串转为数值型
	 */
	public static Number str2Numer(String numberStr, Class<?> numberType) {
		try {
			if ("java.lang.Long".equals(numberType.getName())) {
				return new Long(numberStr);
			} else if ("java.lang.Integer".equals(numberType.getName())) {
				return new Integer(numberStr);
			} else if ("java.lang.Float".equals(numberType.getName())) {
				return new Float(numberStr);
			} else {
				return null;
			}
		} catch (Exception e) {
			return null;
		}
	}

	/**
	 * 截取中文字符串 中字符按两个计算，其它按一个计算
	 * 
	 * @param offset
	 *            起始位置
	 * @param length
	 *            截取长度
	 * @return 源字符串
	 */
	public static String subString(int offset, int length, String srcStr) {
		if (offset < 0)
			offset = 0;
		if (length < 0)
			return srcStr;
		if (srcStr == null)
			return "";
		StringBuilder sb = new StringBuilder();
		double valueLength = 0;
		String chinese = "[\u4e00-\u9fa5]";
		// 获取字段值的长度，如果含中文字符，则每个中文字符长度为2，否则为1
		String lastStr = "";
		boolean addLast = true;
		for (int i = 0; i < srcStr.length(); i++) {
			// 获取一个字符
			String temp = srcStr.substring(i, i + 1);
			// 判断是否为中文字符
			if (temp.matches(chinese)) {
				// 中文字符长度为2
				valueLength += 2;
			} else {
				// 其他字符长度为1
				valueLength += 1;
			}
			if (valueLength > offset && valueLength < offset + length) {
				if (addLast) {
					sb.append(lastStr);
					addLast = false;
				}
				sb.append(temp);
			}
			if (valueLength >= offset + length) {
				return sb.append("...").toString();
			}

			if (!addLast)
				lastStr = temp;
		}
		// 进位取整
		return sb.toString();
	}

	/**
	 * 获取字符串的长度，中文占两个字符,英文数字占一个字符
	 * 
	 * @param value
	 *            指定的字符串
	 * @return 字符串的长度
	 */
	public static double length(String value) {
		double valueLength = 0;
		String chinese = "[\u4e00-\u9fa5]";
		// 获取字段值的长度，如果含中文字符，则每个中文字符长度为2，否则为1
		for (int i = 0; i < value.length(); i++) {
			// 获取一个字符
			String temp = value.substring(i, i + 1);
			// 判断是否为中文字符
			if (temp.matches(chinese)) {
				// 中文字符长度为2
				valueLength += 2;
			} else {
				// 其他字符长度为1
				valueLength += 1;
			}
		}
		// 进位取整
		return Math.ceil(valueLength);
	}

	/**
	 * 去除字符串中的标点符号
	 * 
	 * @param input
	 * @return
	 */
	public static String removeDots(String input) {
		if (input == null)
			return null;
		String trimInput = input.trim();
		int len = trimInput.length();
		StringBuilder sb = new StringBuilder(len);
		for (int i = 0; i < len; i++) {
			char c = trimInput.charAt(i);
			if (Character.UnicodeBlock.of(c) == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION)
				continue;
			if (Character.UnicodeBlock.of(c) == Character.UnicodeBlock.SPACING_MODIFIER_LETTERS)
				continue;
			if (!Character.isLetterOrDigit(c))
				continue;
			sb.append(c);

		}
		return sb.toString();
	}

	public static boolean isDotStr(String input) {
		if (input == null)
			return true;
		String trimInput = input.trim();
		int len = trimInput.length();
		for (int i = 0; i < len; i++) {
			char c = trimInput.charAt(i);
			if (Character.UnicodeBlock.of(c) == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION) {
				continue;
			}
			if (Character.UnicodeBlock.of(c) == Character.UnicodeBlock.SPACING_MODIFIER_LETTERS) {
				continue;
			}
			if (!Character.isLetterOrDigit(c)) {
				continue;
			}
			return false;
		}
		return true;
	}

	public static boolean containsDot(String input) {
		if (input == null)
			return false;
		String trimInput = input.trim();
		int len = trimInput.length();
		for (int i = 0; i < len; i++) {
			char c = trimInput.charAt(i);
			if (Character.UnicodeBlock.of(c) == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION) {
				return true;
			}
			if (Character.UnicodeBlock.of(c) == Character.UnicodeBlock.SPACING_MODIFIER_LETTERS) {
				return true;
			}
			if (!Character.isLetterOrDigit(c)) {
				return true;
			}
		}
		return false;
	}

	/**
	 * @param input
	 * @return
	 */
	public static boolean tagValidate(String input) {
		if (input == null)
			return false;
		String trimInput = input.trim();
		int len = trimInput.length();
		if (len < 2 || len > 10)
			return false;
		if (isNumeric(input)) {
			return false;
		}
		for (int i = 0; i < len; i++) {
			char c = trimInput.charAt(i);
			if (Character.UnicodeBlock.of(c) == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION)
				return false;
			if (Character.UnicodeBlock.of(c) == Character.UnicodeBlock.SPACING_MODIFIER_LETTERS)
				return false;
			if (!Character.isLetterOrDigit(c)) {
				if (c != '・' && c != '·' && c != '(' && c != ')' && c != '（'
						&& c != '）')// 有些字符是允许出现在标签当中的
					return false;
			}

		}
		return true;
	}

	public static String toNormal(String input) {
		input = toDBCCase(input);
		return input.toLowerCase();
	}

	public static String toShow(String input) {
		return toDBCCase(input);
	}

	/**
	 * 全角转半角
	 * 
	 * @param input
	 * @return
	 */
	public static String toDBCCase(String input) {
		if (input == null)
			return null;
		String trimInput = input.trim();
		StringBuilder sb = new StringBuilder(trimInput.length());
		for (int i = 0; i < trimInput.length(); i++) {
			char c = trimInput.charAt(i);
			sb.append(CharUtil.toDBCCase(c));
		}
		return sb.toString();
	}

	/**
	 * 计算短语文本A与短语文本B之间的相似度
	 * 
	 * @param A
	 * @param B
	 * @return
	 */
	public static float similarity(String A, String B) {
		return (sc(A, B) + sc(B, A)) / 2;
	}

	/**
	 * 计算短文本A相对于短语文本B的相似度sc
	 * 
	 * @param A
	 * @param B
	 * @return
	 */
	private static float sc(String A, String B) {
		float sc = 0.0f;
		for (int i = 0; i < A.length(); i++) {
			sc += cc(A, i, B);
		}
		sc /= A.length();
		return sc;
	}

	/**
	 * 计算匹配文字Ai对整体相似度的贡献量
	 * 
	 * @param A
	 * @param i
	 * @param B
	 * @return
	 */
	private static float cc(String A, int i, String B) {
		return (B.length() - posOffset(A, i, B)) / (float) B.length();
	}

	/**
	 * 计算匹配文件Ai的最小匹配偏移值posOffset
	 * 
	 * @param A
	 * @param i
	 * @param B
	 * @return
	 */
	private static int posOffset(String A, int i, String B) {
		int posOffset = B.length();
		for (int j = 0; j < B.length(); j++) {
			if (i - j >= 0 && i - j < posOffset
					&& A.charAt(i) == B.charAt(i - j))
				return j;
			if (i + j < posOffset && A.charAt(i) == B.charAt(i + j))
				return j;
		}
		return posOffset;
	}

	/**
	 * 获取指定HTML标签的指定属性的值
	 * 
	 * @param source
	 *            要匹配的源文本
	 * @param element
	 *            标签名称
	 * @param attr
	 *            标签的属性名称
	 * @return 属性值列表
	 */
	public static List<String> match(String source, String element, String attr) {
		List<String> result = new ArrayList<String>();
		String reg = "<" + element + "[^<>]*?\\s" + attr
				+ "=['\"]?(.*?)['\"]?\\s.*?>";
		Matcher m = Pattern.compile(reg).matcher(source);
		while (m.find()) {
			String r = m.group(1);
			result.add(r);
		}
		return result;
	}

	public final static String getMD5(String s) {
		char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
				'A', 'B', 'C', 'D', 'E', 'F' };
		try {
			byte[] btInput = s.getBytes();
			// 获得MD5摘要算法的 MessageDigest 对象
			MessageDigest mdInst = MessageDigest.getInstance("MD5");
			// 使用指定的字节更新摘要
			mdInst.update(btInput);
			// 获得密文
			byte[] md = mdInst.digest();
			// 把密文转换成十六进制的字符串形式
			int j = md.length;
			char str[] = new char[j * 2];
			int k = 0;
			for (int i = 0; i < j; i++) {
				byte byte0 = md[i];
				str[k++] = hexDigits[byte0 >>> 4 & 0xf];
				str[k++] = hexDigits[byte0 & 0xf];
			}
			return new String(str).toLowerCase();
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}
}